home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / ISSUE07 / YAST / VALIDPTR.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-01-04  |  5.5 KB  |  166 lines

  1. Unit ValidPtr;
  2.  
  3. { Purpose      : Routine to check the validity of a pointer
  4.   Written by   : Hallvard Vassbotn, Oslo, Norway
  5.   E-Mail       : hallvard@falcon.no
  6.   Created      : September 1, 1994
  7.   Requirements : Borland Pascal 7.0 or later
  8.  
  9.   Information to create this unit was found in:
  10.     - Extending DOS Second Edition by Ray Duncan (Addison Wesley, ISBN 0-201-56798-9)
  11.     - Windows Internals by Matt Pietrek          (Addison Wesley, ISBN 0-201-62217-3)
  12.     - Turbo Assembler Quick Reference Guide      (Borland)
  13.     - The Pascal Magazine, issue 5 (page 38-40)
  14.  
  15.   Changes:
  16.  
  17.   04.01.96 : Implemented Julian M. Bucknall's proposed changes
  18.   04.01.96 : Added ValidCodePointer
  19.  
  20. }
  21.  
  22. interface
  23.  
  24. function ValidPointer(P : Pointer; Size: word): boolean;
  25. { -- Returns true if the pointer P is valid and at least Size bytes are
  26.      accessible through it }
  27.  
  28. function ValidCodePointer(P : Pointer; Size: word): boolean;
  29. { -- Returns true if the pointer P is valid and at least Size bytes are
  30.      accessible through it }
  31.  
  32. implementation
  33.  
  34. {$IFDEF MSDOS}
  35.  
  36. { This is the real mode version included for compatability }
  37.  
  38. function ValidPointer(P : Pointer; Size: word): boolean;
  39. { Returns true if the pointer P is not nil. }
  40. begin
  41.   ValidPointer := (P <> nil);
  42. end;
  43.  
  44. function ValidCodePointer(P : Pointer; Size: word): boolean;
  45. { Returns true if the pointer P is not nil. }
  46. begin
  47.   ValidCodePointer := (P <> nil);
  48. end;
  49.  
  50. {$ELSE}
  51.  
  52. type
  53.   { Type used to typecast a pointer to get the segment and offset parts }
  54.   PtrRec = record
  55.     OffsetW  : word;
  56.     SegmentW : word;
  57.   end;
  58.  
  59. function ValidPtrSize(P : Pointer; Size: Word): boolean; assembler;
  60. { Returns true if it is valid to access at least Size bytes through
  61.   the pointer P }
  62. asm
  63.   XOR  AX, AX                 { Set AX to zero     }
  64.   LSL  AX, PtrRec(P).SegmentW { Get limit from LDT, AX=0 if P is not valid }
  65.   MOV  DX, Size               { Get required size... }
  66.   MOV  BX, PtrRec(P).OffsetW  { ...add the offset of the pointer ... }
  67.   ADD  DX, BX                 { ...and store sum in DX }
  68.   CMP  AX, DX                 { Compare with Segment limit }
  69.   MOV  AL, 00
  70.   JB   @ReturnFalse
  71.   INC  AX
  72. @ReturnFalse:
  73. end;
  74.  
  75. function GetSegmentFlags(P : Pointer): word; assembler;
  76. { Returns the access flags for the pointer P }
  77. asm
  78.   XOR  AX, AX                 { Set AX to zero     }
  79.   LAR  AX, PtrRec(P).SegmentW { Get flags from LDT, AX=0 if P is not valid }
  80. end;
  81.  
  82. const
  83.   { These are constants that can be used to get the value of bit-flags
  84.     in the Flags part of an segment descriptor. These flags can be
  85.     accessed by using the LAR assembly instruction }
  86.   dfPresent          = $8000; { The segment is present in memory          }
  87.   dfDPLMask          = $6000; { Mask for Descriptor Privilege Level-field }
  88.   dfSegment          = $1000; { The descriptor is for a segment           }
  89.   dfTypeMask         = $0F00; { Mask to get the Type-field                }
  90.   dfTypeCode         = $0800; { Set for code-segments, otherwise data     }
  91.   dfTypeCodeConform  = $0400; { Conforming code segment                   }
  92.   dfTypeCodeRead     = $0200; { Code-segment can be read for data         }
  93.   dfTypeDataStack    = $0400; { The data segment is a stack (expand-down) }
  94.   dfTypeDataWritable = $0200; { The data segment is writable              }
  95.   dfTypeAccessed     = $0100; { Has the segment ever been accessed ?      }
  96.  
  97. function Is(Flags, Mask: word): boolean;
  98. begin
  99.   Is := ((Flags and Mask) > 0);
  100. end;
  101.  
  102. function ForcePresentFlag(P: pointer): word;
  103. { Returns the access flags for the pointer P.
  104.   If the segment is marked as not-present, try to force it present by
  105.   reading the first byte in the segment. Forcing it present ensures
  106.   that the descriptor contains valid information about size etc.
  107.  
  108.   Thanks to Julian M. Bucknall for his correction (see Pascal Magazine,
  109.   issue 5, page 38-40). }
  110. var
  111.   Flags : word;
  112. begin
  113.   Flags := GetSegmentFlags(P);
  114.   if     Is(Flags, dfSegment) and
  115.      not Is(Flags, dfPresent) and
  116.     (not Is(Flags, dfTypeCode) or
  117.          Is(Flags, dfTypeCodeRead)) then
  118.   begin
  119.     if byte(P^) = 0 then ;
  120.     Flags := GetSegmentFlags(P);
  121.   end;
  122.   ForcePresentFlag := Flags;
  123. end;
  124.  
  125. function ValidDataSegment(P : Pointer): boolean;
  126. { Returns true if P points to a valid data segment }
  127. var
  128.   Flags : word;
  129. begin
  130.   Flags := ForcePresentFlag(P);
  131.   ValidDataSegment :=     Is(Flags, dfSegment)  and
  132.                           Is(Flags, dfPresent)  and
  133.                       not Is(Flags, dfTypeCode) and
  134.                           Is(Flags, dfTypeDataWritable);
  135. end;
  136.  
  137. function ValidCodeSegment(P : Pointer): boolean;
  138. { Returns true if P points to a valid data segment }
  139. var
  140.   Flags : word;
  141. begin
  142.   Flags := ForcePresentFlag(P);
  143.   ValidCodeSegment :=     Is(Flags, dfSegment)  and
  144.                           Is(Flags, dfPresent)  and
  145.                           Is(Flags, dfTypeCode) and
  146.                           Is(Flags, dfTypeCodeRead);
  147. end;
  148.  
  149. function ValidPointer(P : Pointer; Size: word): boolean;
  150. { Returns true if the pointer P is a valid data segment and
  151.   that at least Size bytes can be accessed without a GPF }
  152. begin
  153.   ValidPointer := ValidDataSegment(P) and ValidPtrSize(P, Size-1);
  154. end;
  155.  
  156. function ValidCodePointer(P : Pointer; Size: word): boolean;
  157. { Returns true if the pointer P is a valid data segment and
  158.   that at least Size bytes can be accessed without a GPF }
  159. begin
  160.   ValidCodePointer := ValidCodeSegment(P) and ValidPtrSize(P, Size-1);
  161. end;
  162.  
  163. {$ENDIF}
  164.  
  165. end.
  166.